using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Data.SqlClient;
using Microsoft.ApplicationBlocks.Data;
using System.Data;

namespace Microsoft.SharedSource.SqlServer.MDDE.Repository
{
    public sealed class TemplateConfigurableComponent
    {
        #region Fields

        MDDEPackageTemplate parentTemplate;
        int id;
        string componentName;
        string componentClassId;
        string componentUri;
        string componentType;
        string rowsetType;
        string containsMappings;
        string containsCollections;
        TemplateScalarPropertyCollection scalarProperties;

        #endregion

        #region Properties

        public MDDEPackageTemplate ParentTemplate
        {
            get { return parentTemplate; }
        }

        public int Id
        {
            get { return id; }
            set { id = value; }
        }

        public string ComponentName
        {
            get { return componentName; }
            set { componentName = value; }
        }

        public string ComponentClassId
        {
            get { return componentClassId; }
            set { componentClassId = value; }
        }

        public string ComponentUri
        {
            get { return componentUri; }
            set { componentUri = value; }
        }

        public string ComponentType
        {
            get { return componentType; }
            set { componentType = value; }
        }

        public string RowsetType
        {
            get { return rowsetType; }
            set { rowsetType = value; }
        }

        public string ContainsMappings
        {
            get { return containsMappings; }
            set { containsMappings = value; }
        }

        public string ContainsCollections
        {
            get { return containsCollections; }
            set { containsCollections = value; }
        }

        public TemplateScalarPropertyCollection ScalarProperties
        {
            get
            {
                if (this.scalarProperties == null)
                    this.scalarProperties =
                        new TemplateScalarPropertyCollection(this);
                return this.scalarProperties;
            }
        }

        #endregion

        #region Methods

        public TemplateConfigurableComponent(
            MDDEPackageTemplate parentTemplate,
            string componentUri)
            :
            this(parentTemplate, componentUri, null)
        { }

        public TemplateConfigurableComponent(
            MDDEPackageTemplate parentTemplate,
            string componentUri, SqlTransaction tn)
        {
            this.parentTemplate = parentTemplate;
            this.componentUri = componentUri;
            this.scalarProperties = new TemplateScalarPropertyCollection(this);

            // Get the component info.
            SqlParameter[] sqlParams = new SqlParameter[2];
            sqlParams[0] = new SqlParameter("templateId", parentTemplate.Id);
            sqlParams[1] = new SqlParameter("componentUri", ComponentUri);

            DataSet componentInfo;

            if (tn == null)
                componentInfo = SqlHelper.ExecuteDataset(
                parentTemplate.ParentRepository.RepositoryConnection,
                CommandType.Text,
                Resource.GetTemplateConfigurableComponentInfo, sqlParams);
            else
                componentInfo = SqlHelper.ExecuteDataset(tn,
                CommandType.Text,
                Resource.GetTemplateConfigurableComponentInfo, sqlParams);

            // We could not find the component.
            if (componentInfo.Tables[0].Rows.Count == 0)
                return;

            // We could find the component.
            DataRow r = componentInfo.Tables[0].Rows[0];
            this.componentClassId = r["ComponentClassId"].ToString();
            this.componentName = r["ComponentName"].ToString();
            this.componentType = r["ComponentType"].ToString();
            this.containsMappings = r["ContainsMappings"].ToString();
            this.containsCollections = r["ContainsCollections"].ToString();
            this.id = Convert.ToInt32(r["ComponentId"]);
            this.rowsetType = r["RowsetDescriptorType"].ToString();

            // Fill up the scalar property list.

            DataSet scalarPropertyNames;
            if (tn == null)
                scalarPropertyNames = SqlHelper.ExecuteDataset(
                parentTemplate.ParentRepository.RepositoryConnection,
                CommandType.Text,
                Resource.GetScalarPropertyNames,
                new SqlParameter("@componentId", this.Id));
            else
                scalarPropertyNames = SqlHelper.ExecuteDataset(tn,
                CommandType.Text,
                Resource.GetScalarPropertyNames,
                new SqlParameter("@componentId", this.Id));

            foreach (DataRow r0 in scalarPropertyNames.Tables[0].Rows)
            {
                // Create a scalar property object.
                TemplateScalarProperty objProp =
                    new TemplateScalarProperty(
                    this, r0["PropertyName"].ToString(), tn);

                // Add this property to list.
                this.scalarProperties.Add(objProp);
            }
        }


        internal void Delete(SqlTransaction tn)
        {
            // Delete the template scalar properties.
            foreach (TemplateScalarProperty prop in this.ScalarProperties)
                prop.Delete(tn);

            // Remove the component from the repository.
            SqlHelper.ExecuteScalar(tn,
                CommandType.StoredProcedure,
                "sp_DeleteTemplateComponent",
                new SqlParameter("@componentId", this.Id));
        }

        internal void Update(SqlTransaction tn)
        {
            try
            {
                // Update the configurable component.
                SqlParameter[] spParams = new SqlParameter[3];
                spParams[0] =
                    new SqlParameter("@componentId", this.Id);
                spParams[1] =
                    new SqlParameter("@containsMappings",
                    this.ContainsMappings);
                spParams[2] =
                    new SqlParameter("@containsCollections",
                    this.ContainsCollections);

                // Update the package.
                SqlHelper.ExecuteScalar(tn,
                    CommandType.StoredProcedure,
                    "sp_UpdateTemplateComponent", spParams);

                // Get the template scalar properties list.
                DataSet scalarPropertyNames =
                    SqlHelper.ExecuteDataset(tn,
                    CommandType.Text,
                    Resource.GetScalarPropertyNames,
                    new SqlParameter("@componentId", this.Id));

                List<string> toBeDeleted =
                    new List<string>();

                List<TemplateScalarProperty> toBeInserted =
                    new List<TemplateScalarProperty>();

                Hashtable repositoryScalarProperties = new Hashtable();
                foreach (DataRow r0 in scalarPropertyNames.Tables[0].Rows)
                {
                    repositoryScalarProperties.Add(r0["PropertyName"], null);

                    // Find all the scalar properties that 
                    // are now not present in the collection 
                    // and delete them from the repository.
                    if (!this.ScalarProperties.ContainsScalarProperty(
                        r0["PropertyName"].ToString()))
                        toBeDeleted.Add(r0["PropertyName"].ToString());
                }

                foreach (TemplateScalarProperty prop
                    in this.ScalarProperties)
                {
                    // Find new members in the collection 
                    // and insert them into the repository.
                    if (!repositoryScalarProperties.Contains(
                        prop.PropertyName))
                        toBeInserted.Add(prop);
                }

                // Delete the properties.
                foreach (string propToBeDeleted in toBeDeleted)
                {
                    TemplateScalarProperty prop =
                        new TemplateScalarProperty(
                        this, propToBeDeleted, tn);

                    prop.Delete(tn);
                }

                // Insert new properties.
                foreach (TemplateScalarProperty prop in toBeInserted)
                    prop.Create(tn);

            }
            catch (Exception ex)
            {
                tn.Rollback();
                throw ex;
            }
        }

        internal void Create(SqlTransaction tn)
        {
            SqlParameter[] spParams = new SqlParameter[8];
            spParams[0] = new SqlParameter("@componentClassId",
                this.ComponentClassId);
            spParams[1] = new SqlParameter("@componentName",
                this.ComponentName);
            spParams[2] = new SqlParameter("@templateId",
                this.ParentTemplate.Id);
            spParams[3] = new SqlParameter("@componentUri",
                this.ComponentUri);
            spParams[4] = new SqlParameter("@componentType",
                this.ComponentType);
            spParams[5] = new SqlParameter("@rowsetDescriptorType",
                this.RowsetType);
            spParams[6] = new SqlParameter("@containsMappings",
                this.ContainsMappings);
            spParams[7] = new SqlParameter("@containsCollections",
                                    this.ContainsCollections);

            // Create a new template component.
            this.Id = Convert.ToInt32(
                SqlHelper.ExecuteScalar(tn,
                "sp_CreateTemplateComponent", spParams));

            // Create the scalar properties.
            foreach (TemplateScalarProperty prop in this.ScalarProperties)
            {
                prop.Create(tn);
            }
        }

        #endregion
    }

    public sealed class ConfigurableComponentCollection : IEnumerable
    {
        #region Fields

        private Dictionary<string, TemplateConfigurableComponent>
            configurableComponents =
            new Dictionary<string, TemplateConfigurableComponent>();

        MDDEPackageTemplate parent;

        #endregion

        #region Properties

        public MDDEPackageTemplate Parent
        {
            get { return parent; }
        }

        public TemplateConfigurableComponent this[string componentUri]
        {
            get { return configurableComponents[componentUri]; }
        }

        #endregion

        #region Methods

        internal ConfigurableComponentCollection(MDDEPackageTemplate parent)
        {
            this.parent = parent;
        }

        public void Add(TemplateConfigurableComponent configComp)
        {
            configurableComponents.Add(configComp.ComponentUri, configComp);
        }

        public void Remove(TemplateConfigurableComponent configComp)
        {
            configurableComponents.Remove(configComp.ComponentUri);
        }

        public bool ContainsConfigurableComponent(string componentUri)
        {
            return configurableComponents.ContainsKey(componentUri);
        }

        public void Clear()
        {
            configurableComponents.Clear();
        }

        #endregion

        #region IEnumerable Members

        public IEnumerator GetEnumerator()
        {
            return configurableComponents.Values.GetEnumerator();
        }

        #endregion
    }
}
